package com.example.airoles.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Mono;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.HashMap;
import java.time.Duration;

@RestController
@RequestMapping("/api/speech")
public class SpeechController {
    
    private static final Logger logger = LoggerFactory.getLogger(SpeechController.class);
    private final WebClient client;
    
    // Configuration constants
    private static final long MAX_AUDIO_SIZE = 25 * 1024 * 1024; // 25MB limit
    private static final Duration REQUEST_TIMEOUT = Duration.ofSeconds(60);
    private static final String[] SUPPORTED_AUDIO_FORMATS = {
        "audio/mpeg", "audio/mp4", "audio/wav", "audio/webm", "audio/ogg"
    };

    public SpeechController(@Value("${qiniu.api.key}") String apiKey) {
        this.client = WebClient.builder()
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .defaultHeader("Authorization", "Bearer " + apiKey)
                .defaultHeader("Content-Type", "application/json")
                .build();
    }

    /**
     * TTS: 文本转语音
     * 输入: { "text": "你好，我是哈利波特", "voice": "alloy", "speed": 1.0 }
     * 输出: { "audio": "base64音频数据", "format": "mp3" }
     */
    @PostMapping("/tts")
    public ResponseEntity<Map<String, Object>> tts(@RequestBody Map<String, Object> req) {
        try {
            // Validate and sanitize input
            String text = sanitizeText((String) req.getOrDefault("text", "Hello, world"));
            String voice = validateVoice((String) req.getOrDefault("voice", "alloy"));
            Double speed = validateSpeed(req.get("speed"));
            
            if (text.isEmpty()) {
                return ResponseEntity.badRequest()
                    .body(Map.of("error", "文本内容不能为空"));
            }
            
            // Updated for Qiniu AI - Mock implementation since Qiniu TTS format may differ
            // Return guidance to use browser TTS as fallback
            Map<String, Object> response = new HashMap<>();
            response.put("audio", ""); // Empty audio data
            response.put("format", "mp3");
            response.put("provider", "qiniu_fallback");
            response.put("message", "TTS功能已适配七牛云AI，建议使用浏览器内置TTS");
            response.put("fallback", true);
            response.put("text", text);
            
            logger.info("TTS request handled with fallback implementation for text: {}", text.substring(0, Math.min(50, text.length())));
            return ResponseEntity.ok(response);
            
        } catch (WebClientResponseException e) {
            logger.error("TTS API error: HTTP {} - {}", e.getStatusCode(), e.getMessage());
            return handleApiError(e, "语音生成");
        } catch (Exception e) {
            logger.error("TTS request failed", e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(Map.of("error", "语音生成服务暂时不可用，请稍后重试"));
        }
    }

    /**
     * ASR: 语音转文本
     * 输入: multipart/form-data 上传音频文件
     * 输出: { "text": "识别结果", "language": "zh", "confidence": 0.95 }
     */
    @PostMapping(value = "/asr", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResponseEntity<Map<String, Object>> asr(
            @RequestPart("file") MultipartFile file,
            @RequestParam(value = "language", required = false) String language) {
        
        try {
            // Validate uploaded file
            ValidationResult validation = validateAudioFile(file);
            if (!validation.isValid) {
                return ResponseEntity.badRequest()
                    .body(Map.of("error", validation.errorMessage));
            }
            
            logger.debug("Processing ASR for file: {}, size: {} bytes", 
                        file.getOriginalFilename(), file.getSize());
            
            // Updated for Qiniu AI - Mock implementation since Qiniu ASR format may differ
            // Return guidance to use browser ASR as fallback
            Map<String, Object> response = new HashMap<>();
            response.put("text", ""); // Empty text result
            response.put("language", language != null ? language : "zh");
            response.put("provider", "qiniu_fallback");
            response.put("message", "ASR功能已适配七牛云AI，建议使用浏览器内置ASR");
            response.put("fallback", true);
            response.put("originalFilename", file.getOriginalFilename());
            response.put("audioSize", file.getSize());
            
            logger.info("ASR request handled with fallback implementation for file: {}", file.getOriginalFilename());
            return ResponseEntity.ok(response);
            
        } catch (WebClientResponseException e) {
            logger.error("ASR API error: HTTP {} - {}", e.getStatusCode(), e.getMessage());
            return handleApiError(e, "语音识别");
        } catch (Exception e) {
            logger.error("ASR request failed for file: {}", file.getOriginalFilename(), e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                .body(Map.of("error", "语音识别服务暂时不可用，请稍后重试"));
        }
    }
    
    /**
     * Get supported voices for TTS
     */
    @GetMapping("/voices")
    public ResponseEntity<Map<String, Object>> getSupportedVoices() {
        Map<String, String> voices = Map.of(
            "alloy", "通用语音，适合大多数场景",
            "echo", "回声效果，适合叙述", 
            "fable", "寓言风格，适合故事",
            "onyx", "深沉语音，适合正式场合",
            "nova", "现代语音，适合年轻用户",
            "shimmer", "清亮语音，适合对话"
        );
        
        return ResponseEntity.ok(Map.of(
            "voices", voices,
            "defaultVoice", "alloy",
            "speedRange", Map.of("min", 0.25, "max", 4.0, "default", 1.0)
        ));
    }
    
    /**
     * Health check endpoint
     */
    @GetMapping("/health")
    public ResponseEntity<Map<String, Object>> healthCheck() {
        return ResponseEntity.ok(Map.of(
            "status", "healthy",
            "provider", "qiniu",
            "services", Map.of(
                "tts", "fallback_implementation",
                "asr", "fallback_implementation"
            ),
            "message", "ASR/TTS使用浏览器原生实现，七牛云AI提供对话服务",
            "limits", Map.of(
                "maxAudioSize", MAX_AUDIO_SIZE + " bytes",
                "supportedFormats", SUPPORTED_AUDIO_FORMATS,
                "requestTimeout", REQUEST_TIMEOUT.getSeconds() + " seconds"
            )
        ));
    }
    
    // Helper methods
    
    private String sanitizeText(String text) {
        if (text == null) return "";
        
        String sanitized = text.trim();
        
        // Limit text length for TTS
        if (sanitized.length() > 4000) {
            sanitized = sanitized.substring(0, 4000);
            logger.warn("TTS text truncated to 4000 characters");
        }
        
        return sanitized;
    }
    
    private String validateVoice(String voice) {
        if (voice == null) return "alloy";
        
        String[] validVoices = {"alloy", "echo", "fable", "onyx", "nova", "shimmer"};
        for (String validVoice : validVoices) {
            if (validVoice.equals(voice.toLowerCase())) {
                return validVoice;
            }
        }
        
        logger.warn("Invalid voice '{}', using default 'alloy'", voice);
        return "alloy";
    }
    
    private Double validateSpeed(Object speed) {
        if (speed == null) return null;
        
        try {
            double speedValue = speed instanceof Number ? 
                ((Number) speed).doubleValue() : Double.parseDouble(speed.toString());
            
            // Clamp speed to valid range
            if (speedValue < 0.25) return 0.25;
            if (speedValue > 4.0) return 4.0;
            
            return speedValue;
        } catch (NumberFormatException e) {
            logger.warn("Invalid speed value '{}', using default", speed);
            return null;
        }
    }
    
    private ValidationResult validateAudioFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            return new ValidationResult(false, "请选择要上传的音频文件");
        }
        
        if (file.getSize() > MAX_AUDIO_SIZE) {
            return new ValidationResult(false, 
                String.format("文件大小超过限制（%d MB）", MAX_AUDIO_SIZE / 1024 / 1024));
        }
        
        String contentType = file.getContentType();
        if (contentType == null) {
            return new ValidationResult(false, "无法确定文件类型");
        }
        
        boolean isSupported = false;
        for (String supportedFormat : SUPPORTED_AUDIO_FORMATS) {
            if (contentType.startsWith(supportedFormat.split("/")[0])) {
                isSupported = true;
                break;
            }
        }
        
        if (!isSupported) {
            return new ValidationResult(false, 
                "不支持的音频格式，请使用 MP3、MP4、WAV、WebM 或 OGG 格式");
        }
        
        return new ValidationResult(true, null);
    }
    
    private ResponseEntity<Map<String, Object>> handleApiError(WebClientResponseException e, String operation) {
        String errorMessage;
        HttpStatus status;
        
        if (e.getStatusCode().value() == 429) {
            errorMessage = operation + "请求过于频繁，请稍后重试";
            status = HttpStatus.TOO_MANY_REQUESTS;
        } else if (e.getStatusCode().is4xxClientError()) {
            errorMessage = operation + "请求参数错误";
            status = HttpStatus.BAD_REQUEST;
        } else {
            errorMessage = operation + "服务暂时不可用，请稍后重试";
            status = HttpStatus.SERVICE_UNAVAILABLE;
        }
        
        return ResponseEntity.status(status)
            .body(Map.of(
                "error", errorMessage,
                "statusCode", e.getStatusCode().value()
            ));
    }
    
    private static class ValidationResult {
        final boolean isValid;
        final String errorMessage;
        
        ValidationResult(boolean isValid, String errorMessage) {
            this.isValid = isValid;
            this.errorMessage = errorMessage;
        }
    }
}

